package cn.uncode.rpc.core.protocol.injvm;


import cn.uncode.rpc.common.log.Logger;
import cn.uncode.rpc.common.log.LoggerFactory;
import cn.uncode.rpc.core.AbstractExporter;
import cn.uncode.rpc.core.AbstractInvoker;
import cn.uncode.rpc.core.Exporter;
import cn.uncode.rpc.core.Invoker;
import cn.uncode.rpc.core.Request;
import cn.uncode.rpc.core.Response;
import cn.uncode.rpc.core.URL;
import cn.uncode.rpc.core.protocol.AbstractProtocol;
import cn.uncode.rpc.exception.FrameworkException;
import cn.uncode.rpc.spi.SpiMeta;
import cn.uncode.rpc.util.FrameworkUtil;

/**
 * JVM 节点内部的调用
 * 
 * <pre>
 * 		1) provider 和 referer 相对应 
 * 		2) provider 需要在被consumer refer 之前需要 export
 * </pre>
 * 
 * 
 */
@SpiMeta(name = "injvm")
public class InjvmProtocol extends AbstractProtocol {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(InjvmProtocol.class);
	
	@Override
	public <T> Invoker<T> createInvoker(Class<T> clz, URL url, URL serviceUrl) {
		 return new InjvmInvoker<T>(clz, url, serviceUrl);
	}

	@Override
	public <T> Exporter<T> createExporter(Invoker<T> invoker, URL url) {
		return new InJvmExporter<T>(invoker, url);
	}

    /**
     * injvm provider
     * 
     * @author maijunsheng
     * 
     * @param <T>
     */
    class InJvmExporter<T> extends AbstractExporter<T> {
        public InJvmExporter(Invoker<T> invoker, URL url) {
            super(invoker, url);
        }

        @SuppressWarnings("unchecked")
        @Override
        public void unexport() {
            String protocolKey = FrameworkUtil.getProtocolKey(url);

            Exporter<T> exporter = (Exporter<T>) exporterMap.remove(protocolKey);

            if (exporter != null) {
                exporter.destroy();
            }

            LOGGER.info("InJvmExporter unexport Success: url=" + url);
        }

        @Override
        protected boolean doInit() {
            return true;
        }

        @Override
        public void destroy() {}
    }

    /**
     * injvm consumer
     * 
     */
    class InjvmInvoker<T> extends AbstractInvoker<T> {
        private Exporter<T> exporter;

        public InjvmInvoker(Class<T> clz, URL url, URL serviceUrl) {
            super(url, clz);
        }
        
        @Override
		protected Response doInvoke(Request request) {
        	 if (exporter == null) {
                 throw new FrameworkException("InjvmReferer call Error: provider not exist, url=" + url.getUri());
             }

             return exporter.getInvoker().invoke(request);
		}


        @SuppressWarnings("unchecked")
        @Override
        protected boolean doInit() {
            String protocolKey = FrameworkUtil.getProtocolKey(url);

            exporter = (Exporter<T>) exporterMap.get(protocolKey);

            if (exporter == null) {
            	LOGGER.error("InjvmReferer init Error: provider not exist, url=" + url);
                return false;
            }

            return true;
        }

        @Override
        public void destroy() {}



		
    }




}
